package com.elitel.frame.business.service.common.processor;

import com.elitel.common.utils.IpUtils;
import com.elitel.common.utils.SpringUtils;
import com.elitel.common.utils.StringUtils;
import com.elitel.frame.base.service.BaseQueryfieldService;
import com.elitel.frame.base.service.SysPrjServiceService;
import com.elitel.frame.business.service.common.CommonServerProcessor;
import com.elitel.frame.business.service.common.exception.ServerRequestException;
import com.elitel.frame.core.util.ApplicationContextHelper;
import com.elitel.frame.main.dao.AcAppMapper;
import com.elitel.frame.main.dao.AcAppServiceMapper;
import com.elitel.frame.main.entity.AcApp;
import com.elitel.frame.main.entity.AcAppService;
import com.elitel.frame.main.entity.SysPrjservice;
import org.springframework.util.ObjectUtils;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

import static com.elitel.common.core.constant.RequestConstant.*;

public class RequestCheckProcessor implements CommonServerProcessor {
    /**
     * 管理员标识
     */
    private final String SYSTEM_DIALOG = "ADMIN";
    /**
     * 来源
     */
    private final String FROM_DIALOG = "from";

    /**
     * 时间格式范例
     */
    private String TimePattern = "yyyyMMddHHmmss";
    /**
     * 小时格式范例
     */
    private String HourPattern = "HHmmss";

    /**
     * 请求之前的拦截
     *
     * @param params 参数
     * @return
     */
    @Override
    public void pre(Map params, HttpServletRequest request, HttpServletResponse response) {
        //排除后台管理系统的访问请求 在这里还是从param中获取
        if (SYSTEM_DIALOG.equals(request.getParameter(FROM_DIALOG))) {
            return;
        }
        try {
            // 获取请求头中的TOKEN,如果有值,就将参数中的appCode 赋值给params 如果没有值就不做处理
            this.dealAppCode(request, params);
            // 此前置处理器的通用处理逻辑
            this.generalCheck(params);
            // 此前置处理器的appCode检查逻辑
            this.appCodeCheck(params, request, response);
            // 此前置处理器的serviceStatus检查逻辑
            this.serviceStatusCheck(params);
            // 参数必填校验
            this.requiredCheck(params);

        } catch (Exception e) {
            throw new ServerRequestException(e.getMessage());
        }
    }

    private void dealAppCode(HttpServletRequest request, Map params) {
        String token = request.getHeader(TOKEN);
        if (StringUtils.isNotEmpty(token)) {
            params.put(APP_CODE, token);
        }
    }

    public void generalCheck(Map map) {
        String serviceCode;
        String appCode;
        try {
            serviceCode = (String) map.get(SERVICE_ID);
            appCode = (String) map.get(APP_CODE);
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(ResponseStatus.ILLEGAL_PARAM.initValue());
        }


        if (ObjectUtils.isEmpty(serviceCode)) {
            throw new RuntimeException(ResponseStatus.ILLEGAL_SERVICE_ID.initValue());
        }
        if (ObjectUtils.isEmpty(appCode)) {
            throw new RuntimeException(ResponseStatus.ILLEGAL_APP_CODE.initValue());
        }
        //获取服务基础信息
        SysPrjServiceService sysPrjServiceService = ApplicationContextHelper.getApplicationContext().getBean(SysPrjServiceService.class);
        SysPrjservice sysPrjservice = sysPrjServiceService.getSysPrjserviceByServiceCode(serviceCode);
        if (ObjectUtils.isEmpty(sysPrjservice)) {
            throw new RuntimeException(ResponseStatus.ILLEGAL_SERVICE_ID.initValue());
        }
        //获取访问控制-应用基础信息
        AcAppMapper acAppMapper = ApplicationContextHelper.getApplicationContext().getBean(AcAppMapper.class);
        AcApp acApp = acAppMapper.selectByAppCode(appCode);
        if (ObjectUtils.isEmpty(acApp)) {
            throw new RuntimeException(ResponseStatus.ILLEGAL_APP_CODE.initValue());
        }
    }


    public void appCodeCheck(Map map, HttpServletRequest request, HttpServletResponse response) {
        String serviceCode;
        String appCode;
        try {
            serviceCode = (String) map.get(SERVICE_ID);
            appCode = (String) map.get(APP_CODE);
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(ResponseStatus.ILLEGAL_PARAM.initValue());
        }


        //获取服务基础信息
        SysPrjServiceService sysPrjServiceService = ApplicationContextHelper.getApplicationContext().getBean(SysPrjServiceService.class);
        SysPrjservice sysPrjservice = sysPrjServiceService.getSysPrjserviceByServiceCode(serviceCode);
        //获取访问控制-应用和服务关系
        AcAppServiceMapper acAppServiceMapper = ApplicationContextHelper.getApplicationContext().getBean(AcAppServiceMapper.class);
        List<AcAppService> appServiceList = acAppServiceMapper.getAllByServiceId(sysPrjservice.getGuid());
        //获取访问控制-应用基础信息
        AcAppMapper acAppMapper = ApplicationContextHelper.getApplicationContext().getBean(AcAppMapper.class);
        AcApp acApp = acAppMapper.selectByAppCode(appCode);
        //1.验证AppCode 是否授权
        AcAppService curAcAppService = null;
        for (AcAppService acAppService : appServiceList) {
            if (acAppService.getAppId().equals(acApp.getAppId())) {
                curAcAppService = acAppService;
                break;
            }
        }
        if (ObjectUtils.isEmpty(curAcAppService)) {
            throw new RuntimeException(ResponseStatus.APP_CODE_NOT_AUTHORIZED.initValue());
        }
        //验证IP地址
        String filterIp = acApp.getIp();
        if (ObjectUtils.isEmpty(filterIp)) {
            throw new RuntimeException(ResponseStatus.IPADDR_NOT_AUTHORIZED.initValue());
        } else {
            //校验ip是否符合过滤串规则  过滤IP列表,多个IP‘;’分割，支持后缀'*'通配,支持网段如:`10.10.10.1-10.10.10.99`
            if (!IpUtils.isMatchedIp(filterIp, IpUtils.getIpAddr(request))) {
                throw new RuntimeException(ResponseStatus.IPADDR_NOT_AUTHORIZED.initValue());
            }
        }
        //2.验证AppCode 访问次数
        if (curAcAppService.getDailyCount() > 0 &&
                ServiceAccessTimeLimit.getAndSet(curAcAppService.getAppId(), appCode) > curAcAppService.getDailyCount()) {
            throw new RuntimeException(ResponseStatus.APP_CODE_ACCESS_OVER_LIMIT.initValue());
        }
        //3.验证访问开始和结束日期
        SimpleDateFormat sdfTime = new SimpleDateFormat(TimePattern);
        Date curDate = new Date();
        String curTime = sdfTime.format(curDate);
        if (!ObjectUtils.isEmpty(curAcAppService.getStartTime())) {
            String startTime = sdfTime.format(curAcAppService.getStartTime());
            if (Long.valueOf(curTime) < Long.valueOf(startTime)) {
                throw new RuntimeException(ResponseStatus.ILLEGAL_PARAM.initValue());
            }
        }
        if (!ObjectUtils.isEmpty(curAcAppService.getEndTime())) {
            String endTime = sdfTime.format(curAcAppService.getEndTime());
            if (Long.valueOf(curTime) > Long.valueOf(endTime)) {
                throw new RuntimeException(ResponseStatus.APP_CODE_END_TIME_OVER_TIME.initValue());
            }
        }
        //4.验证访问开始和结束小时
        SimpleDateFormat sdfHour = new SimpleDateFormat(HourPattern);
        String curHour = sdfHour.format(curDate);
        if (!ObjectUtils.isEmpty(curAcAppService.getStartHour())) {
            String startHour = curAcAppService.getStartHour().replaceAll(":", "");
            if (Long.valueOf(curHour) < Long.valueOf(startHour)) {
                throw new RuntimeException(ResponseStatus.APP_CODE_START_HOUR_NOT_START.initValue());
            }
        }
        if (!ObjectUtils.isEmpty(curAcAppService.getEndHour())) {
            String endHour = curAcAppService.getEndHour().replaceAll(":", "");
            if (Long.valueOf(curHour) > Long.valueOf(endHour)) {
                throw new RuntimeException(ResponseStatus.APP_CODE_END_HOUR_OVER_TIME.initValue());
            }
        }
    }

    public void serviceStatusCheck(Map map) {
        String serviceCode;
        try {
            serviceCode = (String) map.get(SERVICE_ID);
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(ResponseStatus.ILLEGAL_PARAM.initValue());
        }

        SysPrjServiceService sysPrjServiceService = ApplicationContextHelper.getApplicationContext().getBean(SysPrjServiceService.class);
        SysPrjservice sysPrjservice = sysPrjServiceService.getSysPrjserviceByServiceCode(serviceCode);
        if (ObjectUtils.isEmpty(sysPrjservice)) {
            throw new RuntimeException(ResponseStatus.SERVICE_NOT_FOUND.initValue());
        }
        //服务状态为禁用
        if (sysPrjservice.getStatus() == 0) {
            throw new RuntimeException(ResponseStatus.SERVICE_NOT_AVAILABLE.initValue());
        }
    }


    public void requiredCheck(Map map) {
        String serviceCode = (String) map.get(SERVICE_ID);
        SysPrjServiceService sysPrjServiceService = SpringUtils.getBean(SysPrjServiceService.class);
        SysPrjservice sysPrjservice = sysPrjServiceService.getSysPrjserviceByServiceCode(serviceCode);
        // 查询必填字段
        BaseQueryfieldService bean = SpringUtils.getBean(BaseQueryfieldService.class);
        Set<String> requiredFields = bean.selectRequiredFieldsByServiceGuid(sysPrjservice.getGuid());
        StringBuilder msg = new StringBuilder();
        if (!ObjectUtils.isEmpty(requiredFields)) {
            // 获取请求参数
            for (String requiredField : requiredFields) {
                Object strings = map.get(requiredField);
                if (ObjectUtils.isEmpty(strings)) {
                    msg.append("参数:").append(requiredField).append("不能为空;");
                }
            }
        }
        if (msg.length() > 0) {
            throw new RuntimeException(msg.toString());
        }
    }


    public enum ResponseStatus {

        ILLEGAL_PARAM("访问受限，请检查参数格式。"),
        ILLEGAL_SERVICE_ID("访问受限，无效的serviceID服务标识。"),
        ILLEGAL_APP_CODE("访问受限，无效的授权码。"),
        SERVICE_NOT_FOUND("访问受限，服务不存在。"),
        SERVICE_NOT_AVAILABLE("访问受限，服务暂未启用。"),
        APP_CODE_NOT_AUTHORIZED("访问受限，应用未授权。"),
        IPADDR_NOT_AUTHORIZED ("访问受限，非授信IP访问。"),
        APP_CODE_ACCESS_OVER_LIMIT("访问受限，授权码已超出当日最大访问上限。"),
        APP_CODE_START_TIME_NOT_START("访问受限，授权码未到访问日期。"),
        APP_CODE_END_TIME_OVER_TIME("访问受限，授权码已过期。"),
        APP_CODE_START_HOUR_NOT_START("访问受限，授权码未到访问时间。"),
        APP_CODE_END_HOUR_OVER_TIME("访问受限，授权码已超出访问时间。。");

        ResponseStatus(String name) {
            this.name = name;
        }

        private String name;

        public String initValue() {
            return name;
        }
    }


    public static class ServiceAccessTimeLimit {
        /**
         * 访问次数记录
         * 约定 Map的Key为 服务和AppCode拼接的字符串 ，Value是日期 yyyyMMdd和访问次数拼接的字符串
         */
        private static Map<String, String> accessTimesMap = new ConcurrentHashMap<>();

        /**
         * 获取当前AppCode 的服务访问次数
         * 约定 Map的Key为 服务和AppCode拼接的字符串 ，Value是日期 yyyyMMdd和访问次数拼接的字符串
         *
         * @param serviceId
         * @param appCode
         * @return
         */
        public static Long getAndSet(String serviceId, String appCode) {
            String key = appCode + "_" + serviceId;
            String oldVal = accessTimesMap.get(key);
            //记录当前日期
            String curDate = new SimpleDateFormat("yyyyMMdd").format(new Date());
            long count = 0;
            if (oldVal != null) {
                String oldDate = oldVal.substring(0, 8);
                if (curDate.equals(oldDate)) {
                    count = Long.parseLong(oldVal.substring(8));
                }
            }
            long newVal = count + 1;
            accessTimesMap.put(key, curDate + newVal);
            return newVal;
        }

    }


}
